package com.morning.dp.tools.dp;


import com.morning.dp.tools.dp.context.AbstractContext;

import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Supplier;

/**
 * (构建者模式)通用对象构建器
 *
 * @author @阿秋
 * @date 2021/1/26
 */
public class DPObjectBuilder<T> extends BaseDesignPattern<DPObjectBuilder<T>> {
    /**
     * 对象全局Context
     */
    private final ObjectContext<T> objectContext;

    private DPObjectBuilder(ObjectContext<T> objectContext) {
        // 构造私有
        super(objectContext);
        this.objectContext = objectContext;
    }

    /**
     * 根据目标类型获取构建器
     *
     * @param targetClass 目标对象类型
     * @param <T>         目标类型
     * @return 返回构建器
     * @throws InstantiationException 反射实例化对象时可能发生的报错（无无参构建函数）
     * @throws IllegalAccessException 反射实例化对象时可能发生的报错（构建函数私有）
     */
    public static <T> DPObjectBuilder<T> startBuild(Class<T> targetClass) throws InstantiationException, IllegalAccessException {
        return startBuild(targetClass.newInstance());
    }

    /**
     * 根据初始目标对象获取构建器
     *
     * @param target 初始目标对象
     * @param <T>    目标对象类型
     * @return 返回初始化目标对象构建器
     */
    public static <T> DPObjectBuilder<T> startBuild(T target) {
        return new DPObjectBuilder<>(new ObjectContext<>(target, new HashMap<>()));
    }

    /**
     * 进行构建处理
     *
     * @param buildHandler 构建处理器
     * @return 返回
     */
    public DPObjectBuilder<T> build(Consumer<ObjectContext<T>> buildHandler) {
        if (!objectContext.isInterrupt()) {
            buildHandler.accept(objectContext);
        }
        return this;
    }

    /**
     * 进行构建处理
     *
     * @param buildHandler 构建处理器
     * @return 返回
     */
    public DPObjectBuilder<T> build(Supplier<Boolean> condition, Consumer<ObjectContext<T>> buildHandler) {
        if (condition.get()) {
            build(buildHandler);
        }
        return this;
    }

    /**
     * 进行构建处理
     *
     * @param buildHandler 构建处理器
     * @return 返回
     */
    public DPObjectBuilder<T> build(boolean condition, Consumer<ObjectContext<T>> buildHandler) {
        if (condition) {
            build(buildHandler);
        }
        return this;
    }

    /**
     * 获取最后构建完成的结果
     *
     * @return 返回构建完成后的目标
     */
    public T get() {
        return objectContext.getTarget();
    }

    public static class ObjectContext<T> extends AbstractContext {
        /**
         * 构建目标对象
         */
        private T target;

        private ObjectContext(T target, Map<String, Object> buildParams) {
            super(buildParams);
            this.target = target;
        }

        public T getTarget() {
            return this.target;
        }

        public void swapTarget(T target) {
            this.target = target;
        }

    }
}
